﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ThapHaNoi
{
    public partial class frmMain : Form
    {
        private bool bStop = true; // biến để dừng
        public int SoDia; // số lượng đĩa
        public int CurrStep = 0;

        public Label[] Dia; // mảng các label biểu diễn cho các đĩa
        // Dia[1] là đĩa trên cùng, nhỏ nhất
        // Dia[i] lớn hơn Dia[i-1]

        public int[] Vitri; // mảng lưu vị trí của từng đĩa (nằm ở cột thứ mấy)
        /* Ví dụ:
         * Vitri[1] = 3 ==> Đĩa số 1 nằm ở cột 3
         * Vitri[6] = 2 ==> Đĩa số 6 nằm ở cột 2
        */

        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Paint(object sender, PaintEventArgs e)
        {
            // VẼ CÁC CỘT
            Graphics gr = e.Graphics;
            Pen pe = new Pen(Color.Red);

            // vẽ cột 1
            Point p1 = new Point(200, 400); 
            Point p2 = new Point(200, 100);
            gr.DrawLine(pe, p1, p2);
            p1.X = 100; p1.Y = 400;
            p2.X = 300; p2.Y = 400;
            gr.DrawLine(pe, p1, p2);

            // cột 2
            p1.X = 500; p1.Y = 400;
            p2.X = 500; p2.Y = 100;
            gr.DrawLine(pe, p1, p2);
            p1.X = 400; p1.Y = 400;
            p2.X = 600; p2.Y = 400;
            gr.DrawLine(pe, p1, p2);

            // cột 3
            p1.X = 800; p1.Y = 400;
            p2.X = 800; p2.Y = 100;
            gr.DrawLine(pe, p1, p2);
            p1.X = 700; p1.Y = 400;
            p2.X = 900; p2.Y = 400;
            gr.DrawLine(pe, p1, p2);
        }

        private void cboSoDia_SelectedIndexChanged(object sender, EventArgs e)
        {
            cmdXoaKetQua.Enabled = false;
            Random rdm = new Random();
            this.Controls.Clear(); // xóa các control

            // add lại các control chuẩn
            this.Controls.Add(cboSoDia);
            this.Controls.Add(cmdGiai);
            this.Controls.Add(lblBuocToiThieu);
            this.Controls.Add(lblBuocHienTai);
            this.Controls.Add(cmdXoaKetQua);

            SoDia = int.Parse(cboSoDia.SelectedItem.ToString());
            lblBuocToiThieu.Text = "Min Steps: " + (Math.Pow(2,SoDia) - 1).ToString(); // số bước chuyển đĩa tối thiểu
            lblBuocHienTai.Text = "Current Step: 0";
            Vitri = new int[SoDia + 1];

            // Thêm các label biểu diễn các đĩa
            Dia = new Label[SoDia + 1];
            for (int i = 1; i <= SoDia; i++)
            {
                Dia[i] = new Label();
                Vitri[i] = 1; // Tất cả các đĩa được khởi tạo đều ở cột 1
                Dia[i].Height = 20; Dia[i].BackColor = Color.FromArgb(rdm.Next(255),rdm.Next(255),rdm.Next(255));
                if (i == 1)
                {
                    Dia[i].Width = 100;
                    Dia[i].Left = 150;
                    Dia[i].Top = 400 - 20 * SoDia;
                }
                else
                {
                    Dia[i].Width = Dia[i - 1].Width + 40;
                    Dia[i].Left = Dia[i - 1].Left - 20;
                    Dia[i].Top = Dia[i - 1].Top + 20;
                }

                this.Controls.Add(Dia[i]);
            }
        }

        private void HieuUng(int CotGoc, int CotDich)
        {
            lblBuocHienTai.Text = "Current Step: " + CurrStep.ToString();
            Label lDia = Dia[1];

            // tìm đĩa cần chuyển
            for (int i = 1; i <= SoDia; i++)
            {
                if (Vitri[i] == CotGoc)
                {
                    lDia = Dia[i];
                    Vitri[i] = CotDich; // đổi đĩa cần chuyển sang cột đích
                    break;
                }
            }

            // tìm số đĩa đã có trong cột đích
            int DichCount = -1;
            for (int i = 1; i <= SoDia; i++)
            {
                if (Vitri[i] == CotDich)
                {
                    DichCount++;
                }
            }

            int speed = 5; // tốc độ di chuyển đĩa
            // nâng đĩa lên trên
            while (lDia.Top > 50)
            {
                lDia.Top -= speed;
                Application.DoEvents();
            }

            // dịch sang trái/phải
            int vitrimoi = CotDich == 1 ? 200 : CotDich == 2 ? 500 : 800;
            if (lDia.Left + lDia.Width / 2 < vitrimoi)
            {
                while (lDia.Left + lDia.Width / 2 < vitrimoi)
                {
                    lDia.Left += speed;
                    Application.DoEvents();
                }
            }
            else if (lDia.Left + lDia.Width / 2 > vitrimoi)
            {
                while (lDia.Left + lDia.Width / 2 > vitrimoi)
                {
                    lDia.Left -= speed;
                    Application.DoEvents();
                }
            }


            // đặt đĩa xuống
            while (lDia.Top < 380 - DichCount * 20)
            {
                lDia.Top += speed;
                Application.DoEvents();
            }
        }

        private void cmdGiai_Click(object sender, EventArgs e)
        {
            if (cmdGiai.Text == "Solve It!")
            {
                if (SoDia > 5)
                    if (MessageBox.Show("Min Steps is very large,\r\nWould you like to continue?", "Caution", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                        // cảnh báo khi số đĩa quá lớn
                        return;

                if (cmdXoaKetQua.Enabled)
                {
                    MessageBox.Show("You must Clear Result first!");
                    return;
                }

                cmdXoaKetQua.Enabled = true;
                CurrStep = 0;
                cmdGiai.Text = "Stop";
                bStop = false;
                Chuyen(SoDia, 1, 3, 2);
                cmdGiai.Text = "Solve It!";
                bStop = true;
            }
            else
            {
                cmdGiai.Text = "Solve It!";
                bStop = true;
            }
        }

        private void Chuyen(int SoDia, int CotNguon, int CotDich, int CotTG)
        {
            if (SoDia > 0)
            {
                Chuyen(SoDia - 1, CotNguon, CotTG, CotDich);
                CurrStep++;
                if (bStop) return; // ngừng giải nếu nhấn Stop
                HieuUng(CotNguon, CotDich);
                Chuyen(SoDia - 1, CotTG, CotDich, CotNguon);
                if (bStop) return; // ngừng giải nếu nhấn Stop
            }
        }

        private void cmdXoaKetQua_Click(object sender, EventArgs e)
        {
            cboSoDia_SelectedIndexChanged(sender, e);
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            cboSoDia.Items.Clear();
            // Nap cac gia tri cho cboSoDia
            for (int i = 1; i <= 25; i++)
            {
                cboSoDia.Items.Add(i);
            }
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            bStop = true;
        }
    }
}
